// 实现这个项目的构建任务
const {
  src,
  series,
  parallel,
  watch,
  dest
} = require('gulp');

const del = require('del');
const browser = require('browser-sync');

const sass = require('gulp-sass')(require('sass'));
const eslint = require('gulp-eslint');
const sasslint = require('gulp-sass-lint');
const cache = require('gulp-cached');
const babel = require('gulp-babel');
const swig = require('gulp-swig');
const imagemins = require('gulp-imagemin');
const useref = require('gulp-useref');
const task_js = require('gulp-uglify');
const task_css = require('gulp-clean-css');
const task_html = require('gulp-htmlmin');
const task_if = require('gulp-if');
const ghPages = require('gulp-gh-pages');
// error TypeError: Cannot read property '0' of null
// cd node_modules/gulp-gh-pages/
// npm i --save gift@0.10.2

const data = require('./swig.data.json')

/**
 * @desc serve config
 */
const instruct_key = ["serve", "start", "build", "deploy"]
const instruct_value = {
  "port": 8088,
  "open": true,
  "dir": ['temp', 'src', 'public'],
  "routes": {
    '/node_modules': 'node_modules'
  },
  // dev pord
  "build": 'dev',
  "branch": 'gh-pages', // 现在只支持已有的分支
}

try {
  const [, path, t, ...config] = process.argv;

  // 确认是gulp脚本
  if (!path.includes('.bin/gulp')) {
    throw new Error('----')
  };

  // 确认启动指令
  const instruct = instruct_key.find(item => item === t);

  // 不符合指令 直接返回
  if (!instruct) {
    throw new Error('----')
  };

  config.some(c => {
    const [key, value] = c.split(":");

    switch (t) {
      case 'serve':
        if (key === '--port' && 0 <= Number(value) <= 65535) {
          instruct_value["port"] = Number(value);
        };

        if (key === '--open' && ['true', 'false'].includes(value)) {
          instruct_value["open"] = 'true' === value;
        };

        return true;
      case 'start':
        // 生产环境启动
        instruct_value["dir"] = 'dist';
        instruct_value["routes"] = {};

        return true
      case 'build':
        if (['--prod', '--production'].includes(value)) {
          instruct_value["build"] = 'prod'; // 生产环境
        }
        return true
      case 'deploy':
        if (key === '--branch') {
          instruct_value["branch"] = value;
        };

        return true
      default:
        throw new Error('')
    }
  })

} catch (error) {
  console.log('error');
}


/**
 * @desc init 
 */

// eslint
const lintRules = {
  // 解决eslint检查箭头函数不通过
  'parser': 'babel-eslint',
  rules: {
    // 2 -> error 1 -> waring
    'no-empty-function': 1,
    'no-empty': 1,
  },
  globals: [
    'jQuery',
    '$'
  ],
  envs: [
    'browser'
  ]
}

// serve
const bs = browser.create();


/**
 * @task
 */
const styles = () => {
  return src('src/**/*.scss', {
      base: 'src'
    })
    .pipe(sass())
    .pipe(dest('temp'))
    .pipe(bs.reload({
      stream: true
    }))
};

const pages = () => {
  return src('src/**/*.html', {
      base: 'src'
    })
    .pipe(swig({
      data,
      defaults: {
        cache: false
      }
    }))
    .pipe(dest('temp'))
    .pipe(bs.reload({
      stream: true
    }))
};

const scripts = () => {
  return src('src/**/*.js', {
      base: 'src'
    })
    .pipe(babel({
      presets: ['@babel/preset-env']
    }))
    .pipe(dest('temp'))
    .pipe(bs.reload({
      stream: true
    }))
};

const images = () => {
  return src('src/assets/images/*', {
      base: 'src'
    })
    .pipe(imagemins())
    .pipe(dest('dist'));
};

const fonts = () => {
  return src('src/assets/fonts/*', {
      base: 'src'
    })
    .pipe(imagemins())
    .pipe(dest('dist'))
};

const public = () => {
  return src('public/*', {
      base: 'public'
    })
    .pipe(dest('dist'))
};

const userefs = () => {
  return src('temp/*.html', {
      base: 'temp'
    })
    .pipe(useref({
      searchPath: ['temp', '.']
    }))
    .pipe(task_if(/\.js$/, task_js()))
    .pipe(task_if(/\.css$/, task_css()))
    .pipe(task_if(/\.html$/, task_html({
      collapseWhitespace: true,
      minifyCSS: true,
      minifyJS: true
    })))
    .pipe(dest('dist'))
};

const js_lint = () => {
  return src('src/**/*.js')
    .pipe(cache('eslint'))
    .pipe(eslint(lintRules))
    .pipe(eslint.format())
    .pipe(eslint.failAfterError());
};

const scss_lint = () => {
  return src('src/**/*.scss')
    .pipe(cache('sasslint'))
    .pipe(sasslint())
    .pipe(sasslint.format())
    // 出错时 终止任务
    .pipe(sasslint.failOnError())
}


const serves = () => {

  watch('src/**/*.scss', styles);
  watch('src/**/*.js', scripts);
  watch('src/**/*.html', pages);

  watch(['src/asstes/images/*', 'src/asstes/fonts/*', 'public/*'], bs.reload)

  bs.init({
    notify: false,
    port: instruct_value["port"],
    open: instruct_value["open"],
    server: {
      baseDir: instruct_value["dir"],
      routes: instruct_value["routes"]
    },
  })
};

const deploys = () => {
  return src('dist/**')
    .pipe(ghPages({
      remoteUrl: "https://github.com/Can-Chen/gulp-gh-pages.git",
      branch: instruct_value["branch"],
      push: true,
    }));
}


// clean
// 清理dist&temp文件.
const clean = () => {
  return del(['dist', 'temp'])
};

// lint
// 检查样式和脚本文件。
const lint = parallel(js_lint, scss_lint);

// compile
// 编译样式、脚本和页面文件
const compile = series(clean, lint, parallel(pages, scripts, styles));

// serve
// 使用自动服务器以开发模式运行应用程序
const serve = series(compile, serves);

// build
// 将用于生产的应用程序生成到dist文件夹。它在生产模式下缩小源，以获得最佳性能。
const build = series(
  clean,
  parallel(
    public,
    images,
    fonts,
    series(
      parallel(
        pages,
        scripts,
        styles
      ),
      userefs
    )
  )
)

// start
// 以生产模式运行项目
const start = series(build, serve);

// deploy
// 将dist文件夹部署到GitHub页面。
const deploy = series(build, deploys);

module.exports = {
  compile,
  lint,
  clean,
  serve,
  build,
  start,
  deploy
}
